package io.elegant
import android.annotation.SuppressLint
import com.google.protobuf.Any
import io.elegant.sessions.BaseSession
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okio.BufferedSink
import java.io.IOException
import java.io.InputStream

fun OkHttpClient.upload(session: BaseSession, cs: CoroutineScope, cbProgress: Any, stream: InputStream, mimeType: String, filename: String?, url: String, onFinish: (Exception?) -> Unit) {
    val fileRequestBody = object: RequestBody() {
        private fun sendProgressCallback(value: Float) = session.apply {
            val progress = value.toAny()
            cs.launch {
                cbProgress.sendCallback(progress)
            }
        }
        @SuppressLint("Recycle")
        override fun contentType() = mimeType.toMediaType()
        override fun writeTo(sink: BufferedSink) {
            val len = contentLength()
            var curr = 0L
            stream.use {
                val buf = ByteArray(10240)
                var read = it.read(buf)
                while (read > -1) {
                    sink.write(buf, 0, read)
                    curr += read
                    sendProgressCallback(curr / len.toFloat() * 100)
                    read = it.read(buf)
                }
            }
        }
        override fun contentLength() = stream
            .available()
            .toLong()
    }
    val body = MultipartBody
        .Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", filename, fileRequestBody)
        .build()
    val request = Request
        .Builder()
        .url(url)
        .post(body)
        .build()
    newCall(request)
        .enqueue(object: Callback {
            override fun onFailure(call: Call, e: IOException) = cs.launch {
                onFinish(e)
            }.let {  }
            override fun onResponse(call: Call, response: Response) = cs.launch {
                onFinish(null)
            }.let {  }
        })
}
